package com.lucien.Tree;

/**
 * @Author cxy
 * @Date 2020/11/4 16:25
 * @Version 1.0
 * 线索化二叉树
 */
public class ThreadedBinaryTreeDemo {
    public static void main(String[] args) {
        ThreadedHeroNode root = new ThreadedHeroNode(1, "一休");
        ThreadedHeroNode node2 = new ThreadedHeroNode(3, "三弟");
        ThreadedHeroNode node3 = new ThreadedHeroNode(6, "六狗");
        ThreadedHeroNode node4 = new ThreadedHeroNode(8, "八哥");
        ThreadedHeroNode node5 = new ThreadedHeroNode(10, "十子");
        ThreadedHeroNode node6 = new ThreadedHeroNode(14, "十四爹");

        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);

        ThreadedBinaryTree binaryTree = new ThreadedBinaryTree();
        binaryTree.setRoot(root);
        binaryTree.infixthreadedNodes();

        ThreadedHeroNode node5Left = node5.getLeft();
        ThreadedHeroNode node5Right = node5.getRight();
        System.out.println("node5前驱节点==" + node5Left);
        System.out.println("node5后继节点==" + node5Right);
    }
}

//定义ThreadedBinaryTree二叉树 实现了线索化功能的二叉树
class ThreadedBinaryTree {
    private ThreadedHeroNode root;
    //为了实现线索化，需要创建一个指向当前节点的前驱节点的指针
    //在递归进行线索化是，pre总是保留前一个节点
    private ThreadedHeroNode pre = null;

    public void setRoot(ThreadedHeroNode root) {
        this.root = root;
    }

    public void prethreadedNodes1() {
        this.prethreadedNodes1(root);
    }

    public void infixthreadedNodes() {
        this.infixthreadedNodes(root);
    }

    public void postthreadedNodes() {
        this.postthreadedNodes(root);
    }


    /**
     * 编写对二叉树进行前序线索化的方法
     *
     * @param node 当前需要线索化的节点
     */
    public void prethreadedNodes1(ThreadedHeroNode node) {
        if (node == null) {
            return;
        }
        //2、线索化当前节点
        //处理当前节点的前驱节点
        if (node.getLeft() == null) {
            //让当前节点的左指针指向前驱节点
            node.setLeft(pre);
            //修改当前节点的做指针类型，指向前驱节点
            node.setLeftType(1);
        }
        //处理后继节点
        if (pre != null && pre.getRight() == null) {
            //让前驱节点的右指针指向当前节点
            pre.setRight(node);
            //修改前驱节点的右指针类型
            pre.setRightType(1);
        }
        //***没处理一个节点后，让当前节点是下一个节点的前驱节点
        pre = node;
        //1、线索化左子树
        prethreadedNodes1(node.getLeft());

        //3、线索化右子树
        prethreadedNodes1(node.getRight());
    }

    /**
     * 编写对二叉树进行中序线索化的方法
     *
     * @param node 当前需要线索化的节点
     */
    public void infixthreadedNodes(ThreadedHeroNode node) {
        if (node == null) {
            return;
        }
        //1、线索化左子树
        infixthreadedNodes(node.getLeft());
        //2、线索化当前节点
        //处理当前节点的前驱节点
        if (node.getLeft() == null) {
            //让当前节点的左指针指向前驱节点
            node.setLeft(pre);
            //修改当前节点的做指针类型，指向前驱节点
            node.setLeftType(1);
        }
        //处理后继节点
        if (pre != null && pre.getRight() == null) {
            //让前驱节点的右指针指向当前节点
            pre.setRight(node);
            //修改前驱节点的右指针类型
            pre.setRightType(1);
        }
        //***没处理一个节点后，让当前节点是下一个节点的前驱节点
        pre = node;
        //3、线索化右子树
        infixthreadedNodes(node.getRight());
    }

    /**
     * 编写对二叉树进行后序线索化的方法
     *
     * @param node 当前需要线索化的节点
     */
    public void postthreadedNodes(ThreadedHeroNode node) {
        if (node == null) {
            return;
        }
        //1、线索化左子树
        postthreadedNodes(node.getLeft());
        //3、线索化右子树
        postthreadedNodes(node.getRight());
        //2、线索化当前节点
        //处理当前节点的前驱节点
        if (node.getLeft() == null) {
            //让当前节点的左指针指向前驱节点
            node.setLeft(pre);
            //修改当前节点的做指针类型，指向前驱节点
            node.setLeftType(1);
        }
        //处理后继节点
        if (pre != null && pre.getRight() == null) {
            //让前驱节点的右指针指向当前节点
            pre.setRight(node);
            //修改前驱节点的右指针类型
            pre.setRightType(1);
        }
        //***没处理一个节点后，让当前节点是下一个节点的前驱节点
        pre = node;

    }

    //前序遍历
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else {
            System.out.println("当前二叉树为空");
        }
    }

    //中序遍历
    public void infixOrder() {
        if (this.root != null) {
            this.root.infixOrder();
        } else {
            System.out.println("当前二叉树为空");
        }
    }

    //后序遍历
    public void postOrder() {
        if (this.root != null) {
            this.root.postOrder();
        } else {
            System.out.println("当前二叉树为空");
        }
    }

    //前序查找
    public ThreadedHeroNode preOrderSearch(int no) {
        if (root != null) {
            return root.preOrderSearch(no);
        } else {
            return null;
        }
    }

    //前序查找
    public ThreadedHeroNode infixOrderSearch(int no) {
        if (root != null) {
            return root.infixOrderSearch(no);
        } else {
            return null;
        }
    }

    //前序查找
    public ThreadedHeroNode postOrderSearch(int no) {
        if (root != null) {
            return root.postOrderSearch(no);
        } else {
            return null;
        }
    }

    //删除节点
    public void delNode(int no) {
        if (root != null) {
            //如果root只有一个节点，立即判断root是否就是需要删除的节点
            if (root.getNo() == no) {
                root = null;
            } else {
                //递归删除
                root.delNode(no);
            }
        } else {
            System.out.println("空树不能删除");
        }
    }
}


//先创建HeroNode节点
class ThreadedHeroNode {
    private int no;
    private String name;
    private ThreadedHeroNode left;
    private ThreadedHeroNode right;
    /*
        1、如果leftType == 0 表示指向的是左子树，如果是 1 表示指向前驱节点
        2、如果rightType == 0 表示指向的是右子树，如果是 1 表示指向后继节点
     */
    private int leftType;
    private int rightType;

    public ThreadedHeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public ThreadedHeroNode getLeft() {
        return left;
    }

    public void setLeft(ThreadedHeroNode left) {
        this.left = left;
    }

    public ThreadedHeroNode getRight() {
        return right;
    }

    public void setRight(ThreadedHeroNode right) {
        this.right = right;
    }

    public int getLeftType() {
        return leftType;
    }

    public void setLeftType(int leftType) {
        this.leftType = leftType;
    }

    public int getRightType() {
        return rightType;
    }

    public void setRightType(int rightType) {
        this.rightType = rightType;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }

    //前序遍历
    public void preOrder() {
        //先输出父节点
        System.out.println(this);
        //递归向左子树前序遍历
        if (this.left != null) {
            this.left.preOrder();
        }
        //递归向右子树前序遍历
        if (this.right != null) {
            this.right.preOrder();
        }
    }

    //中序遍历
    public void infixOrder() {
        //递归向左子树中序遍历
        if (this.left != null) {
            this.left.infixOrder();
        }
        //输出父节点
        System.out.println(this);
        //递归向右子树中序遍历
        if (this.right != null) {
            this.right.infixOrder();
        }
    }

    //后序遍历
    public void postOrder() {
        //递归向左子树后序遍历
        if (this.left != null) {
            this.left.postOrder();
        }
        //递归向右子树后序遍历
        if (this.right != null) {
            this.right.postOrder();
        }
        //输出父节点
        System.out.println(this);
    }

    /**
     * 前序遍历查找
     *
     * @param no 需要查找的序号 no
     * @return 如果找到则返回HeroNode，否则返回null
     */
    public ThreadedHeroNode preOrderSearch(int no) {
        System.out.println("前序遍历查找~~~");
        //比较当前节点是不是
        if (this.no == no) {
            return this;
        }
        //先判断当前节点的做子节点是否为空，不为空则递归前序查找
        //如果前序查找 找到节点 则返回
        ThreadedHeroNode resNode = null;
        if (this.left != null) {
            resNode = this.left.preOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;
        }
        //若左边前序查找完没有找到，先判断当前节点的右子节点是否为空 不为空则递归前序查找
        //找到则返回 没有则返回null
        if (this.right != null) {
            resNode = this.right.preOrderSearch(no);
        }
        return resNode;
    }

    /**
     * 中序查找
     *
     * @param no 需要查找的序号 no
     * @return 如果找到则返回HeroNode，否则返回null
     */
    public ThreadedHeroNode infixOrderSearch(int no) {
        ThreadedHeroNode resNode = null;
        //向左遍历查找
        if (this.left != null) {
            resNode = this.left.infixOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;
        }
        System.out.println("中序遍历查找~~~");
        //当前节点
        if (this.no == no) {
            return this;
        }
        //向右遍历查找
        if (this.right != null) {
            resNode = this.right.infixOrderSearch(no);
        }
        return resNode;
    }

    /**
     * 后序查找
     *
     * @param no 需要查找的序号 no
     * @return 如果找到则返回HeroNode，否则返回null
     */
    public ThreadedHeroNode postOrderSearch(int no) {
        ThreadedHeroNode resNode = null;
        //向左遍历查找
        if (this.left != null) {
            resNode = this.left.postOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;
        }
        //向右遍历查找
        if (this.right != null) {
            resNode = this.right.postOrderSearch(no);
        }
        if (resNode != null) {
            return resNode;
        }
        System.out.println("后序遍历查找~~~");
        //左右子树都没，查找当前节点
        if (this.no == no) {
            return this;
        }
        return resNode;
    }

    /*
      递归删除节点
        1、如果删除的节点是叶子节点，则删除该节点
        2、如果删除的节点是飞叶子节点，则删除该子树
    */
    public void delNode(int no) {
        //如果当前节点的左子节点不为空，并且左子节点 就是要删除的节点 将this.left = null;并且返回(结束递归)
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        //如果当前节点的右子节点不为空，并且右子节点 就是要删除的节点 将this.right = null;并且返回(结束递归)
        if (this.right != null && this.right.no == no) {
            this.right = null;
            return;
        }
        //如果前面都没找到需要删除的节点 就需要向左子树进行递归删除
        if (this.left != null) {
            this.left.delNode(no);
        }
        //如果前面都没找到需要删除的节点 就需要向左子树进行递归删除
        if (this.right != null) {
            this.right.delNode(no);
        }
    }
}



